# 公司：安徽银杰
# 作者：李伟

"""
class Student:
    def __init__(self, name, age, id):
        # 封装核心属性（用_前缀标识为“私有”，提示外部不要直接访问）
        self._name = name
        self._age = age
        self._id = id

    def get_student_info(self):
        return f"学生的信息如下：姓名：{self._name},年龄：{self._age},学号：{self._id}"

    def update_age(self, new_age):
        if 0 < new_age < 100:
            self._age = new_age
            return f"年龄已经更新{new_age}"
        else:
            return "年龄输入不合法"


data = Student("李华", -190, 100001)
# print(data.get_student_info())

print(data.update_age(-230))
print(data.get_student_info())
# print(data.age)  #私有化之后 外部无法直接调用
"""""
# 需求描述
# 定义一个Calculator类，封装常用的算术运算，实现以下功能：
# 初始化时，不需要传入参数（计算器本身不需要 “初始数据”，只需要 “计算能力”）。
# 提供 4 个方法：add(a, b)（加法）、subtract(a, b)（减法）、multiply(a, b)（乘法）、divide(a, b)（除法）。
# 除法需要处理 “除数为 0” 的异常（避免程序崩溃，体现封装的健壮性）。
# 核心考点

"""""
class Calculator:
    def __init__(self):
        pass
    def add(self,a,b):
        return a + b
    def subtract(self,a,b):
        return  a - b
    def divide(self,a,b):
        try:
            if a != 0:
                return  a / b
            else:
                return "除数不可为零"
        except Exception as e:
            raise f"{e}"

data =Calculator()
print(data.add(1, 2))
print(data.subtract(1, 2))
print(data.divide(0, 2))
"""""


# 练习题 3：「图书」类（带属性保护）
# 需求描述
# 定义一个Book类，管理图书的核心信息，要求：
# 属性包括「书名」（不可修改）、「作者」、「价格」（只能是正数）、「是否借出」（默认未借出）。
# 提供borrow_book()方法：如果未借出，标记为 “已借出” 并提示成功；如果已借出，提示 “已被借出”。
# 提供return_book()方法：如果已借出，标记为 “未借出” 并提示成功；如果未借出，提示 “未被借出”。
# 提供get_book_status()方法：返回图书的当前状态（如：《Python入门》- 作者：李四，价格：59.0元，状态：未借出）。


# 由于会有多种类，所以需要初始化类属性，便于后续类方法使用。
class Book:
    def __init__(self, title, author, price):
        self._title = title  # 书名不可修改，不提供set方法
        self._author = author
        # 价格初始化时就校验合法性
        if price > 0:
            self._price = price
        else:
            raise ValueError("价格必须为正数！")  # 初始化时非法直接报错
        self._is_borrowed = False  # 默认未借出

    # 书名只有get方法（不可修改）
    def get_title(self):
        return self._title

    # 作者提供get和set方法（可修改）
    def get_author(self):
        return self._author

    def set_author(self, new_author):
        self._author = new_author

    # 价格修改时校验合法性
    def set_price(self, new_price):
        if new_price > 0:
            self._price = new_price
            print(f"价格已更新为：{new_price}元")
        else:
            print("价格必须为正数！")

    # 借阅逻辑
    def borrow_book(self):
        if not self._is_borrowed:
            self._is_borrowed = True
            print(f"《{self._title}》借阅成功！")
        else:
            print(f"《{self._title}》已被借出，无法借阅！")

    # 归还逻辑
    def return_book(self):
        if self._is_borrowed:
            self._is_borrowed = False
            print(f"《{self._title}》归还成功！")
        else:
            print(f"《{self._title}》未被借出，无需归还！")

    # 获取当前状态
    def get_book_status(self):
        status = "已借出" if self._is_borrowed else "未借出"
        return f"《{self._title}》- 作者：{self._author}，价格：{self._price}元，状态：{status}"


# 测试代码
book1 = Book("Python入门", "李四", 59.0)
print(book1.get_book_status())  # 未借出
book1.borrow_book()  # 借阅成功
print(book1.get_book_status())  # 已借出
book1.borrow_book()  # 提示已借出
book1.set_price(-10)  # 价格不合法
book1.set_author("王五")
print(book1.get_book_status())  # 作者已更新


# 条件表达式（conditional expression），也常被称为 “三元运算符”
# 它的作用是根据条件（condition）的真假，返回两个值中的一个，是一种简洁的分支判断写法。

# 案例一
# 如果下雨了，就带伞；否则，就不带伞
# result = "带伞" if 下雨 else "不带伞"

# 案例二：
age = 18
# 如果年龄大于等于18，就是"成年人"；否则是"未成年人"
# status = "成年人" if age >= 18 else "未成年人"
# 繁琐写法：
# if age >= 18:
#     status = "成年人"
# else:
#     status = "未成年人"



# 练习题 4：「购物车」类（封装集合数据）
# 需求描述
# 定义一个ShoppingCart类，模拟电商购物车的基本功能：
# 初始化时，购物车为空（内部用列表或字典存储商品）。
# 提供add_item(product_name, price, quantity=1)方法：添加商品到购物车（支持指定数量，默认 1 件；如果商品已存在，数量累加）。
# 提供remove_item(product_name)方法：从购物车中删除指定商品（如果商品不存在，提示 “商品未在购物车中”）。
# 提供calculate_total()方法：计算购物车中所有商品的总金额。
# 提供show_cart()方法：显示购物车中的所有商品（如：商品：苹果，单价：5.0元，数量：2）。

class ShoppingCart:
    def __init__(self):
        # 内部用字典存储商品：key=商品名，value=(单价, 数量)
        self._items = {}

    # 添加商品（已存在则累加数量）
    def add_item(self, product_name, price, quantity=1):
        if quantity <= 0:
            print("数量必须为正数！")
            return
        if product_name in self._items:
            # 商品已存在，累加数量
            current_quantity = self._items[product_name][1]
            self._items[product_name] = (price, current_quantity + quantity)
        else:
            # 新商品，直接添加
            self._items[product_name] = (price, quantity)
        print(f"已添加 {quantity} 件《{product_name}》到购物车")

    # 删除商品
    def remove_item(self, product_name):
        if product_name in self._items:
            del self._items[product_name]
            print(f"已从购物车删除《{product_name}》")
        else:
            print(f"《{product_name}》未在购物车中")

    # 计算总价
    def calculate_total(self):
        total = 0.0
        for price, quantity in self._items.values():
            total += price * quantity
        return total

    # 显示购物车
    def show_cart(self):
        if not self._items:
            print("购物车为空！")
            return
        print("=== 购物车商品 ===")
        for product_name, (price, quantity) in self._items.items():
            print(f"商品：{product_name}，单价：{price}元，数量：{quantity}")
        print(f"=== 购物车总价：{self.calculate_total()}元 ===")


# 测试代码
cart = ShoppingCart()
cart.add_item("苹果", 5.0, 2)
cart.add_item("牛奶", 3.5, 3)
cart.show_cart()  # 显示商品和总价
cart.add_item("苹果", 5.0, 1)  # 累加苹果数量
cart.show_cart()  # 苹果数量变为3
cart.remove_item("牛奶")
cart.show_cart()
print(f"最终总价：{cart.calculate_total()}元")

# 练习题 5：「银行账户」类（带私有方法）
# 需求描述
# 定义一个BankAccount类，模拟银行账户的基础操作，要求：
# 初始化时，传入「账户名」「账号」「初始余额」（余额默认为 0，且必须非负）。
# 提供deposit(amount)方法：存款（金额必须为正，存款后余额增加）。
# 提供withdraw(amount)方法：取款（金额必须为正，且不能超过当前余额，取款后余额减少）。
# 提供check_balance()方法：查询当前余额。
# 新增要求：封装一个私有方法_validate_amount(amount)，用于校验存款 / 取款金额是否为正数（避免在deposit和withdraw中重复写校验逻辑，体现封装的 “代码复用”）。

class BankAccount:
    def __init__(self, account_holder, account_number, balance=0.0):
        self._account_holder = account_holder
        self._account_number = account_number
        if balance >= 0:
            self._balance = balance
        else:
            raise ValueError("初始余额不能为负数！")

    # 私有方法：校验金额是否为正数（仅类内部调用）
    def _validate_amount(self, amount):
        if not isinstance(amount, (int, float)):
            print("金额必须是数字！")
            return False
        if amount <= 0:
            print("金额必须为正数！")
            return False
        return True

    # 存款
    def deposit(self, amount):
        if self._validate_amount(amount):
            self._balance += amount
            print(f"存款成功！当前余额：{self._balance}元")

    # 取款
    def withdraw(self, amount):
        if not self._validate_amount(amount):
            return
        if amount > self._balance:
            print("余额不足，取款失败！")
            return
        self._balance -= amount
        print(f"取款成功！当前余额：{self._balance}元")

    # 查询余额
    def check_balance(self):
        print(f"账户{self._account_number}（{self._account_holder}）当前余额：{self._balance}元")
        return self._balance


# 测试代码
account1 = BankAccount("张三", "6222020100012345678", 1000.0)
account1.check_balance()  # 初始余额1000元
account1.deposit(500)  # 存款500，余额1500
account1.withdraw(800)  # 取款800，余额700
account1.withdraw(1000)  # 余额不足
account1.deposit(-200)  # 金额不合法
# account1._validate_amount(100) # 外部调用私有方法（不推荐，Python虽不强制禁止，但违背封装原则）